package main

import "fmt"

func main() {
	// example-chan中，其中计算平方的squarer函数在两个串联Channels的中间，因此拥有两个channel类型的参数，
	// 一个用于输入一个用于输出。
	// 两个channel都拥有相同的类型，但是它们的使用方式相反：一个只用于接收，另一个只用于发送。参数的名字in和out已经
	// 明确表示了这个意图，但是并无法保证squarer函数向一个in参数对应的channel发送数据或者从一个out参数对应的channel
	// 接收数据。
	//
	// 这种场景是典型的。当一个channel作为一个函数参数时，它一般总是被专门用于只发送或者只接收。
	//
	// 为了表明这种意图并防止被滥用，Go语言的类型系统提供了单方向的channel类型，分别用于只发送或只接收的channel。
	// 类型chan<- int表示一个只发送int的channel，只能发送不能接收。相反，类型<-chan int表示一个只接收int的channel，
	// 只能接收不能发送。（箭头<-和关键字chan的相对位置表明了channel的方向。）这种限制将在编译期检测。
	//
	// 因为关闭操作只用于断言不再向channel发送新的数据，所以只有在发送者所在的goroutine才会调用close函数，
	// 因此对一个只接收的channel调用close将是一个编译错误。
	//
	// 本例子为改进的版本，这一次参数使用了单方向channel类型：

	naturals := make(chan int)
	squares := make(chan int)
	go counter(naturals)
	go squarer(squares, naturals)
	printer(squares)

}

func counter(out chan<- int) {
	for x := 0; x < 100; x++ {
		out <- x
	}
	close(out)
}

func squarer(out chan<- int, in <-chan int) {
	for v := range in {
		out <- v * v
	}
	close(out)
}

func printer(in <-chan int) {
	for v := range in {
		fmt.Println(v)
	}
}
